package com.zhiyou.app.config.oss;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.StrUtil;
import com.aliyun.oss.ClientBuilderConfiguration;
import com.aliyun.oss.OSS;
import com.aliyun.oss.OSSClientBuilder;
import com.aliyun.oss.OSSException;
import com.aliyun.oss.common.auth.CredentialsProviderFactory;
import com.aliyun.oss.common.auth.EnvironmentVariableCredentialsProvider;
import com.aliyun.oss.common.comm.SignVersion;
import com.aliyun.oss.model.PutObjectRequest;
import com.aliyuncs.exceptions.ClientException;
import com.zhiyou.app.common.exception.BizException;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.ByteArrayInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;

/**
 * oss工具类
 */
@Slf4j
public class OssUtil implements OssService {
    private final OssProperties ossProperties;
    private final OSS ossClient;
    // OSS域名特征（阿里云），可根据实际厂商扩展（如腾讯云cos、AWS S3等）
    private static final String ALI_OSS_DOMAIN_SUFFIX = "aliyuncs.com";
    private final static String TEMP_BUCKET_NAME = "zyzz-temp";
    public final static String TEMP_URL_PREFIX = "https://zyzz-temp.oss-cn-chengdu.aliyuncs.com/";


    public OssUtil(OssProperties ossProperties) throws ClientException {
        this.ossProperties = ossProperties;
        // 从环境变量中获取访问凭证。运行本代码示例之前，请确保已设置环境变量OSS_ACCESS_KEY_ID和OSS_ACCESS_KEY_SECRET。
        EnvironmentVariableCredentialsProvider credentialsProvider = CredentialsProviderFactory.newEnvironmentVariableCredentialsProvider();
        // 创建OSSClient实例。
        // 当OSSClient实例不再使用时，调用shutdown方法以释放资源。
        ClientBuilderConfiguration clientBuilderConfiguration = new ClientBuilderConfiguration();
        clientBuilderConfiguration.setSignatureVersion(SignVersion.V4);
        ossClient = OSSClientBuilder.create().endpoint(ossProperties.getEndpoint()).credentialsProvider(credentialsProvider).clientConfiguration(clientBuilderConfiguration).region(ossProperties.getRegion()).build();
    }

    @Override
    public boolean deleteFile(String url) {
        OssUrlInfo ossUrlInfo = parseOssUrl(url);
        assert ossUrlInfo != null;
        return ossClient.deleteObject(ossUrlInfo.getBucket(), ossUrlInfo.getPath() + ossUrlInfo.getFile()).getResponse().getStatusCode() == 204;
    }

    @Override
    public String uploadFile(String fileName, String path, InputStream uploadFile) throws ClientException {
        if (StrUtil.isBlank(path)) {
            path = ossProperties.getBucketPath();
        }
        return doUpload(TEMP_BUCKET_NAME, fileName, path, uploadFile);
    }

    @Override
    public String uploadFile(String fileName, String path, String url) {
        try {
            return uploadFile(fileName, path, new URL(url).openStream());
        } catch (ClientException e) {
            throw new BizException("ossclient初始化失败", e.getErrMsg());
        } catch (IOException e) {
            throw new BizException("文件流读取失败", e.getMessage());
        }
    }

    @Override
    public String uploadFile(String fileName, String path, byte[] bytes) {
        try {
            return uploadFile(fileName, path, new ByteArrayInputStream(bytes));
        } catch (ClientException e) {
            throw new BizException("ossclient初始化失败", e.getErrMsg());
        }
    }

    @Override
    public String useFile(String tempFileUrl, String path) {
        if (tempFileUrl.startsWith(TEMP_URL_PREFIX)) {
            if (path == null) {
                throw new BizException("使用文件保存路径path不能为空");
            }
            String sourceObjectName = tempFileUrl.substring(TEMP_URL_PREFIX.length(), tempFileUrl.lastIndexOf("?") == -1 ? tempFileUrl.length() : tempFileUrl.lastIndexOf("?"));
            String destinationObjectName = path + "/" + FileUtil.mainName(tempFileUrl) + "." + FileUtil.extName(tempFileUrl);
            //拷贝文件
            ossClient.copyObject(TEMP_BUCKET_NAME, sourceObjectName, ossProperties.getBucketName(), destinationObjectName);
            //删除源文件
            ossClient.deleteObject(TEMP_BUCKET_NAME, sourceObjectName);
            //返回新文件路径
            return "https://" + ossProperties.getBucketName() + "." + ossProperties.getEndpoint() + "/" + destinationObjectName;
        }
        return tempFileUrl;
    }

    @Override
    public String uploadAndUseFile(String fileName, String path, InputStream uploadFile) {
        return doUpload(ossProperties.getBucketName(), fileName, path, uploadFile);
    }

    /**
     * 上传文件
     *
     * @param bucketName  bucket名称
     * @param objectName  对象名称
     * @param path        路径
     * @param inputStream 流
     * @return 文件路径
     */
    private String doUpload(String bucketName, String objectName, String path, InputStream inputStream) {
        try {
            String mainName = FileUtil.mainName(objectName);
            String extName = FileUtil.extName(objectName);
            objectName = path + "/" + mainName + "_" + System.currentTimeMillis() + "." + extName;
            if (objectName.startsWith("/")) {
                objectName = objectName.substring(1);
            }
            // 创建PutObjectRequest对象。
            PutObjectRequest putObjectRequest = new PutObjectRequest(bucketName, objectName, inputStream);

            // 如果需要上传时设置存储类型和访问权限，请参考以下示例代码。
            // ObjectMetadata metadata = new ObjectMetadata();
            // metadata.setHeader(OSSHeaders.OSS_STORAGE_CLASS, StorageClass.Standard.toString());
            // metadata.setObjectAcl(CannedAccessControlList.Private);
            // putObjectRequest.setMetadata(metadata);
            ossClient.putObject(putObjectRequest);
            return "https://" + bucketName + "." + ossProperties.getEndpoint() + "/" + objectName;
        } catch (OSSException oe) {
            System.out.println("Caught an OSSException, which means your request made it to OSS, " + "but was rejected with an error response for some reason.");
            System.out.println("Error Message:" + oe.getErrorMessage());
            System.out.println("Error Code:" + oe.getErrorCode());
            System.out.println("Request ID:" + oe.getRequestId());
            System.out.println("Host ID:" + oe.getHostId());
        }
        return null;
    }

    @Data
    static class OssUrlInfo {
        /**
         * OSS存储桶（Bucket）
         */
        private String bucket;
        /**
         * 文件路径（不含文件名，如 "photos/2024/"）
         */
        private String path;
        /**
         * 文件名（含扩展名，如 "summer.jpg"）
         */
        private String file;
        /**
         * 原始URL
         */
        private String originalUrl;
    }


    /**
     * 提取OSS URL中的bucket、path、file
     *
     * @param ossUrl OSS文件URL（支持虚拟主机/路径前缀两种格式）
     * @return 解析结果（OssUrlInfo），解析失败时字段为null
     */
    public static OssUrlInfo parseOssUrl(String ossUrl) {
        // 1. 入参校验
        if (StrUtil.isBlank(ossUrl)) {
            return null;
        }

        OssUrlInfo result = new OssUrlInfo();
        result.setOriginalUrl(ossUrl);

        try {
            // 2. 预处理URL：移除查询参数（如 ?x-oss-process=style/xxx）
            String urlWithoutParams = ossUrl.substring(0, !ossUrl.contains("?") ? ossUrl.length() : ossUrl.indexOf("?"));
            URL url = new URL(urlWithoutParams);
            // 域名（如 my-bucket.oss-cn-beijing.aliyuncs.com）
            String host = url.getHost();
            // 域名后的完整路径（如 /photos/2024/summer.jpg）
            String path = url.getPath();

            // 3. 提取Bucket（区分两种格式）
            String bucket;
            if (host.contains(ALI_OSS_DOMAIN_SUFFIX) && host.split("\\.").length > 3) {
                // 格式1：虚拟主机格式（bucket在子域名）
                bucket = host.split("\\.")[0];
            } else {
                // 格式2：路径前缀格式（bucket在路径第一段）
                // 移除路径开头的 "/"，按 "/" 分割（如 "my-bucket/photos/2024/summer.jpg" → 数组[0]为bucket）
                String[] pathSegments = StrUtil.removePrefix(path, "/").split("/");
                bucket = (pathSegments.length > 0) ? pathSegments[0] : null;
            }
            result.setBucket(bucket);

            // 4. 提取完整的文件路径（path + file，即OSS中的objectKey，不含bucket）
            String objectKey = getObjectKey(host, path, bucket);
            if (StrUtil.isBlank(objectKey)) {
                return result;
            }

            // 5. 拆分path（不含文件名）和file（含扩展名）
            int lastSlashIndex = objectKey.lastIndexOf("/");
            if (lastSlashIndex == -1) {
                // 无路径，直接在bucket根目录（如 "summer.jpg"）
                result.setPath("");
                result.setFile(objectKey);
            } else {
                // 有路径（如 "photos/2024/summer.jpg" → path="photos/2024/", file="summer.jpg"）
                String fileDir = objectKey.substring(0, lastSlashIndex + 1); // 保留末尾 "/"，符合路径规范
                String fileName = objectKey.substring(lastSlashIndex + 1);
                result.setPath(fileDir);
                result.setFile(fileName);
            }

        } catch (Exception e) {
            // 捕获URL解析异常（如非法URL格式）
            e.printStackTrace();
            return null;
        }

        return result;
    }

    /**
     * 从URL中提取OSS的objectKey（即不含bucket的完整路径+文件名）
     */
    private static String getObjectKey(String host, String path, String bucket) {
        if (StrUtil.isBlank(path) || StrUtil.isBlank(bucket)) {
            return null;
        }

        if (host.contains(ALI_OSS_DOMAIN_SUFFIX) && host.split("\\.").length > 3) {
            // 格式1：虚拟主机格式 → objectKey就是域名后的path（移除开头 "/"）
            return StrUtil.removePrefix(path, "/");
        } else {
            // 格式2：路径前缀格式 → objectKey是路径中bucket后的部分（移除开头的 "/bucket/"）
            String bucketWithSlash = "/" + bucket + "/";
            return StrUtil.removePrefix(path, bucketWithSlash);
        }
    }

    // 测试示例
    public static void main(String[] args) {
        // 测试格式1：虚拟主机格式
        String url1 = "https://my-bucket.oss-cn-beijing.aliyuncs.com/photos/2024/summer.jpg?x-oss-process=style/thumb";
        OssUrlInfo info1 = parseOssUrl(url1);
        System.out.println("格式1解析结果：" + info1);
        // 输出：OssUrlInfo(bucket=my-bucket, path=photos/2024/, file=summer.jpg, originalUrl=...)

        // 测试格式2：路径前缀格式
        String url2 = "https://oss-cn-beijing.aliyuncs.com/my-bucket/music/2024/spring.mp3";
        OssUrlInfo info2 = parseOssUrl(url2);
        System.out.println("格式2解析结果：" + info2);
        // 输出：OssUrlInfo(bucket=my-bucket, path=music/2024/, file=spring.mp3, originalUrl=...)

        // 测试根目录文件（无路径）
        String url3 = "https://my-bucket.oss-cn-shanghai.aliyuncs.com/readme.txt";
        OssUrlInfo info3 = parseOssUrl(url3);
        System.out.println("根目录文件解析：" + info3);
        // 输出：OssUrlInfo(bucket=my-bucket, path=, file=readme.txt, originalUrl=...)
    }
}
